/**
 * 用户管理系统后端主服务器文件
 * 
 * 这个文件是后端API的入口点，负责：
 * 1. 创建Express服务器
 * 2. 配置中间件（处理跨域、JSON解析等）
 * 3. 连接数据库
 * 4. 定义API路由
 * 5. 启动服务器监听
 */

// 引入必要的依赖包
import express from 'express'  // Web框架，用于创建API服务
import cors from 'cors'        // 处理跨域请求（让前端能访问后端）
import dotenv from 'dotenv'    // 管理环境变量（数据库密码等敏感信息）
import bodyParser from 'body-parser'  // 解析HTTP请求体

// 引入数据库连接配置
import { sequelize, initDatabase } from './config/database.js'

// 引入API路由
import userRoutes from './routes/users.js'

// 加载环境变量配置
// 为什么要用环境变量？把敏感信息（如数据库密码）放在.env文件中，不会暴露在代码里
dotenv.config()

// 创建Express应用实例
const app = express()

// 配置中间件
// 什么是中间件？请求到达路由处理函数之前，先经过中间件处理

// CORS中间件：解决跨域问题
// 什么是跨域？浏览器安全机制，前端页面只能访问同源（相同协议、域名、端口）的API
// 允许 Vue3 (5173) 与 Vue2 (5174) 前端访问
// 小白解释：只有在这里“白名单”的网址，浏览器才允许访问我们的后端接口
// 支持从 .env 里用逗号分隔多个来源，例如：
// CORS_ORIGIN=http://localhost:5173,http://localhost:5174,http://localhost:5175
// 小白解释：白名单就是“允许访问后端的前端地址列表”。开发时可能端口变动，这里都放进来。
const envOrigins = (process.env.CORS_ORIGIN || 'http://localhost:5173')
  .split(',')
  .map(o => o.trim())
  .filter(Boolean)
const allowedOrigins = new Set([
  ...envOrigins,
  'http://localhost:5174',
  'http://localhost:5175',
  'http://localhost:5176'
])

app.use(cors({
  origin: (origin, callback) => {
    // 有些请求（例如 Postman、服务器自身）没有 origin，这里直接放行
    if (!origin) return callback(null, true)
    if (allowedOrigins.has(origin)) return callback(null, true)
    // 不在白名单的，拒绝并提示
    return callback(new Error('Not allowed by CORS: ' + origin))
  },
  credentials: true
}))

// body-parser中间件：解析JSON格式的请求体
// 为什么要解析？HTTP请求体是字符串，需要转换成JavaScript对象才能使用
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: true }))

// 请求日志中间件：记录每个HTTP请求
// 为什么要记录？方便调试和监控API调用情况
app.use((req, res, next) => {
  console.log(`[${new Date().toLocaleString()}] ${req.method} ${req.url}`)
  next()  // 继续执行下一个中间件或路由处理函数
})

// 定义API路由
// 什么是路由？根据URL路径和HTTP方法，调用对应的处理函数
app.use('/api/users', userRoutes)  // 用户相关的API路由

// 根路由：测试服务器是否正常运行
app.get('/', (req, res) => {
  res.json({
    message: '用户管理系统后端API服务运行正常！',
    version: '1.0.0',
    timestamp: new Date().toISOString()
  })
})

// 错误处理中间件：捕获所有未处理的错误
// 为什么要统一处理？避免程序崩溃，给前端返回友好的错误信息
app.use((err, req, res, next) => {
  console.error('服务器错误：', err)
  res.status(500).json({
    error: '服务器内部错误',
    message: err.message || '未知错误',
    timestamp: new Date().toISOString()
  })
})

// 定义服务器启动函数
const startServer = async () => {
  try {
    // 初始化数据库（自动创建库、连接、创建表、插入示例数据）
    // 小白解释：这一步会自动建表并塞入几条测试数据，方便你马上打开前端看到效果
    console.log('正在初始化数据库...')
    await initDatabase()
    console.log('数据库初始化完成！')
    
    // 启动HTTP服务器
    const PORT = process.env.PORT || 3000  // 从环境变量读取端口，默认3000
    app.listen(PORT, () => {
      console.log(`🚀 服务器启动成功！`)
      console.log(`📡 服务地址：http://localhost:${PORT}`)
      console.log(`📡 API文档：http://localhost:${PORT}/api`)
      console.log(`⏰ 启动时间：${new Date().toLocaleString()}`)
    })
    
  } catch (error) {
    console.error('❌ 服务器启动失败：', error)
    process.exit(1)  // 退出进程
  }
}

// 启动服务器
startServer()

// 优雅关闭：处理进程终止信号
// 为什么要优雅关闭？确保数据库连接正确关闭，避免数据丢失
process.on('SIGINT', async () => {
  console.log('\n🛑 收到终止信号，正在关闭服务器...')
  try {
    await sequelize.close()  // 关闭数据库连接
    console.log('✅ 数据库连接已关闭')
    process.exit(0)
  } catch (error) {
    console.error('❌ 关闭数据库连接失败：', error)
    process.exit(1)
  }
})